# Author:  wuxianfeng
# Company: songqin
# File:    basePage.py
# Date:    22-7-15
# Time:    下午 8:48
from time import strftime

from selenium.webdriver.remote.webelement import WebElement

from common.comm_driver import CommDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys

from configs.env import Env
from utils.handle_path import LetCodePath
from utils.handle_yaml import get_yaml_data


'''
知识点:

'''


class BasePage:
    """
    PO1: The public methods represent the services that the page offers

    """

    def __init__(self):
        # 首先保证得到一个浏览器实例
        self.driver = CommDriver().get_driver()

        # 第一步： 每个页面类要去获取元素的定位器，名字 ； 获取所有页面的元素
        # self.locators = get_yaml_data(LetCodePath.configs_path / 'allelements.yaml')
        # 第二步： 每个页面都只获取自己页面的元素即可
        # 分配到页面 各取所需
        self.locators = get_yaml_data(LetCodePath.configs_path / 'allelements.yaml')[self.__class__.__name__]
        # 第三步： 如果你现在要去用这些元素，  self.locators['元素名']
        # 再次优化，变成类的属性
        # self.locators  字典
        # {'mainpage_text': ['css selector', '.no-redirect']}
        # key:元素名  ：  定位器 locator
        for element_name, locator in self.locators.items(): # self.locators必须有内容，为空会报错
            setattr(self, element_name, locator)  # 反射 给实例设置属性元素名其值为locator

    def open_url(self, url):  # 这个不是必须要写的，提供了一个二次封装的入口
        """
        打开某个具体的网页
        Args:
            url:  要打开的网页

        Returns: None

        """
        self.driver.get(url)  # 对于非法的 www.baidu.com 符合用户习惯的，你可以封装一下

    def get_element_old(self, locator) -> WebElement:  # -> 定义返回值类型是WebElement
        """
        定位元素
        Args:
            locator: 元素的定位器

        Returns: WebElement

        """
        import warnings
        warnings.warn('this method has been deprecated,please use get_element instead!', DeprecationWarning)
        return self.driver.find_element(*locator)

    def get_element(self, locator,
                    timeout=Env.TIME_OUT,
                    poll_frequency=Env.FREQUENCY,
                    desc=None,
                    elements=False):
        """
        显式定位元素，异常捕获日志
        Args:
            locator: 元素的定位器
            timeout: 元素显式等待最大超时时间
            poll_frequency: 轮询频率
            desc: 待定位元素的描述
            elements：是否要定位多个元素，默认是定位一个（False）
        Returns: 元素

        """
        try:
            if not elements:
                return WebDriverWait(self.driver, timeout, poll_frequency). \
                    until(EC.visibility_of_element_located(locator))
            else:
                return WebDriverWait(self.driver, timeout, poll_frequency). \
                    until(EC.visibility_of_all_elements_located(locator))
                        # 返回了一个列表   find_elements的结果
        except:
            # 截图  避免重复（时间）  有意义（desc）
            curtime = strftime('%Y%m%d%H%M%S')  # 很多同学大写搞错
            self.driver.save_screenshot(f'{LetCodePath.screenshots_path}/{desc}{curtime}.png')
            # 日志
            from utils.handle_loguru import log
            log.error(f'{desc}元素定位不到')

    def input_text_old(self, locator, text):
        """
        在指定的元素上输入内容(已废弃)
        Args:
            locator: 元素的定位器
            text:  要输入的内容

        Returns:  None

        """
        # self.driver.find_element(*locator).send_keys(text)
        import warnings
        warnings.warn('this method has been deprecated,please use input_text instead!', DeprecationWarning)
        self.get_element(locator).send_keys(text)

    def input_text(self, locator, text, append=False, desc=None):

        """
        PO6: Different results for the same action are modelled as different methods
            打破了这个原则，不同的结果用同一个方法来体现
        在指定的元素上输入内容,根据参数来选择追加或者不追加
        Args:
            locator: 元素的定位器
            text:  要输入的内容
            append: 是否追加的标记，True 追加，否则不追加
            desc: 写元素名称（描述） 传递给get_element方法
        Returns:  None

        """
        # self.driver.find_element(*locator).send_keys(text)
        if append:
            self.get_element(locator, desc=desc).send_keys(text)
        else:
            self.get_element(locator, desc=desc).clear()
            self.get_element(locator, desc=desc).send_keys(text)

    def hotkey(self, element: WebElement, key_name: str):
        """
        使用键盘输入热键
        Args:
            key_name: 使用Keys中的各个热键名，可以写成TAB

        Returns:

        """
        key = getattr(Keys, key_name)
        element.send_keys(key)


    def click_element(self, locator, desc=None):
        """
        点击指定定位器指向的元素
        Args:
            locator: 元素的定位器

        Returns: None

        """
        self.get_element(locator, desc=desc).click()

    def get_element_text(self, locator, desc=None):
        """
        获取指定元素的文本
        Args:
            locator: 元素的定位器

        Returns: text 元素的文本

        """
        return self.get_element(locator, desc=desc).text

    def get_element_texts(self, locator, desc=None):
        """
        获取指定元素的文本
        Args:
            locator: 元素的定位器

        Returns: text 元素的文本

        """
        # 列表推导式
        return [element.text for element in self.get_element(locator, desc=desc,elements=True)]

    def get_element_attribute(self, locator, attitude, desc=None):
        """
        获取指定元素的属性
        Args:
            locator: 元素的定位器
            attitude: 属性名
            desc:

        Returns: 元素属性值
        """
        element = self.get_element(locator, desc=desc)
        attitude_value = element.get_attribute(attitude)
        return attitude_value

    def if_contains_url(self,partial_url_text):
        # 上节课提到的，可以用显式等待来封装
        # 参考DEMO
        # 不加except中的return False不可，会TimeOut
        try:
            return WebDriverWait(self.driver,Env.TIME_OUT,Env.POLL_FREQUENCY).\
                until(EC.url_contains(partial_url_text))
        except:
            return False

    def clear_element_text(self, locator, desc=None):
        """

        Args:
            locator:
            desc:

        Returns:

        """
        self.get_element(locator, desc=desc).clear()

if __name__ == '__main__':
    test_flag = 3
    if test_flag == 3:  # 演示日志和截图
        test_page = BasePage()
        test_page.open_url('http://124.223.33.41:38090/login')
        test_page.input_text(('id', 'usernam'), '松勤老师', desc='用户名')
    if test_flag == 2:  # 能否登录 POLLY
        test_page = BasePage()
        test_page.open_url('http://124.223.33.41:38090/login')
        test_page.input_text(('id', 'username'), '松勤老师')
        test_page.input_text(('id', 'password'), '123456')
        test_page.click_element(('id', 'btnLogin'))

    if test_flag == 1:  # 删除线的演示

        BasePage().input_text_old()
